ES6面试总结(持续更新~)

您所在的位置:网站首页 es6 get set ES6面试总结(持续更新~)

ES6面试总结(持续更新~)

#ES6面试总结(持续更新~)| 来源: 网络整理| 查看: 265

本篇文章面试官问到es6时,你可以按照套路一一回答面试官的问题,给面试官你基础还不错的印象。

请问你熟悉哪些ES6新特性? let和const 变量的解构赋值 字符串、数组、函数、对象、运算符拓展 Symbol Proxy Reflect Promise对象、async函数、Genertor函数语法 Iterator和for...of循环 class的基本语法 class继承 Module的语法 Moule的语法 Moudle的加载实现 - 区别篇 1. 请问let,var,const区别?

块级作用域方面: let和const有块级作用域,var没有块级作用域,但有函数作用域

变量提升方面:var支持变量提升,const和let不支持,且let会出现暂时性死区的问题

声明赋值方面:var可以重复声明,const和let不能重复声明,且const一旦初始化数据就不能赋值否则报错。

2. 箭头函数和普通函数的区别? 箭头函数没有自己的this对象,它的this是它执行上下文的this 不可以当作构造函数,也就是说不能new,否则会抛出一个错误 没有argument 不可以使用yield命令,因此箭头函数不能用作Generator函数。 3. 介绍下Set、Map、WeakSet和WeakMap的区别? - Set

它类似于数组,成员的值是唯一的,没有重复的值,set本身是一个构造函数,用于生成Set数据结构,主要的方法有add、delete、has,可以遍历,应用场景数组去重。

- weakSet

它与Set类似,也是不重复的值的集合。

它与Set的区别是:

WeakSet的成员只能是对象,而不能是其他类型的值。

image-20211001162400224.png

没有size属性,不能遍历

image-20211001162645485.png

WeakSet中对象都是弱引用,垃圾回收机制考虑WeakSet对该对象的引用,也就是说,如果其他对象都不在引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑对象还存在WeakSet之中。 应用场景:WeakSet适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在WeakSet里面的引用也会消失,这样不容易造成内存泄漏 - Map

本质是键值对的集合(hash结构),键可以是对象,优化了Object。主要的方法为get、set,has、delete,可以遍历。可以干各种类型转换。

- WeakMap

它与Map类似,它和Map的区别:

键名只接受对象

image-20211001162906850.png

没有size属性,不能遍历

image-20211001163033239.png

是弱引用,不被垃圾回收机制回收 面试官:如何理解垃圾回收机制?(填坑)谈工作原理即可

工作原理:垃圾回收机制依赖引用计数,如果一个值不为0,垃圾回收机制就不会释放这块内存。结束使用该值,就会释放该值内存。如果忘记取消引用,就会导致内存无法释放,进而可能引起内存泄漏。

4. async await对比promise的优缺点?

async/await优点:

它做到真正的串行的同步写法,代码阅读更简单 对于条件语句和其他流程比较友好,可以直接写到判断条件 function a() { return new Promise((resolve, reject) => { setTimeout(() => { resolve(111) }, 1111) }) }; async function f() { try { if ( await a() === 111) { console.log('yes, it is!') // 会打印 } } catch (err) { // ... } } 复制代码 处理复杂流程时,在代码清晰度方面有优势

async/await缺点:

无法处理promise返回对象的reject对象,要借助try...catch... 用await可能会导致性能问题,因为await会阻塞代码,之后的代码也许不依赖于前者,但仍然需要等待前者的完成,导致代码失去并发性。 try...catch...内部的变量无法传递给下一个try...catchPromise和then/catch内部定义的变量

promise的一些问题:

一旦执行,就无法中途取消,链式调用多个then不能随便跳出来 错误无法在外部捕捉,只能在内部预判处理,如果内部进行预判处理,如果不设置回调函数,Promise内部抛出的错误,不能反应到外部 Promise内部如何执行,检测很难,当处于pending状态时,无法得知目前进展到哪一个阶段 5. 简述一下Promise,async&await两者者的区别? promise通过链式调用,直接在then中返回一个promise来进行成功之后的回调函数,用catch来做错误处理 async是Generator函数的语法糖,async/await则将其变成同步的写法,即可以用try-catch捕获,简洁,可读性更高,写法更优雅 6. CommonJS和ES6模块的区别 CommonJS模块输出是一个值的拷贝(浅拷贝),ES6模块输出是值的引用 CommonJS是运行时加载,ES6模块是编译时输出接口 CommonJS模块的require()是同步加载模块,ES6模块的import命令是异步加载,有一个独立依赖的解析模块阶段

CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值

ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。

补充点:可能面试官会问你还见过哪些规范

就可以说一下AMD和CMD

AMD规范的模块化:用 require.config()指定引用路径等,用define()定义模块,用require()加载模块。

CMD规范的模块化:用define()定义模块, seajs.use 引用模块。

- 字符、数组、对象、函数、运算符拓展篇 1. 你是如何理解数组对象内容解构?

你可以举如下几个例子:

数组结构 let [a1,a2,a3] = [1,2,3] //a1 = 1; a2 = 2; a3 = 3; 复制代码 对象解构 let {name,age} = {name:'meteor', age:8} // name = 'meteor' age = 8 复制代码 复杂解构 let [{age}] = [{age:8,name:'xx'},'江西',[1,2,3]] //age = 8 注意对象解构 复制代码 默认赋值 let {age = 5} = {age:8,name;'xx'} //age = 8 如果没有age字段age = 5 复制代码 常用函数给默认参数 //以前 function(){var a = a || 5} //现在 function(a = 5){} 复制代码 2. 请问字符串增添哪些方法? 反引号(可以拼接一些变量) let name = 'kk'; let age = 20; let str = `${name}${age}岁了` console.log(str); //kk20岁了 复制代码 includes方法 //判断字符串是否包含某个字符串 let str = '23123S'; str.includes('3S')//true 复制代码 endsWith、startsWith方法 //判断字符串是否以某一个字符串开始或结束 var a = '1AB42342D' console.log(a.startsWith('1A')) //true console.log(a.endsWith('2d')) //false 复制代码 3. 数组新增哪些方法,并指明它的用法?

Array.from()将类数组转化数组(对象,Set,Map)

Array.of()用于将一组值,转换为数组

Array.of(3, 11, 8) // [3,11,8] Array.of(3) // [3] Array.of(3).length // 1 复制代码 Array.fill()填充数组 Array.find()和findIndex() [1, 4, -5, 10].find((n) => n < 0) // -5 [1, 4, 5, 10].find((n) => n < 0) //undefined [1, 5, 10, 15].findIndex(function(value, index, arr) { return value > 9; }) // 2 [1, 5, 10, 15].findIndex(function(value, index, arr) { return value > 15; }) // -1 复制代码 entries(),keys()和values()遍历数组 includes()表示某个数组是否包含给定的值 [1, 2, 3].includes(2) // true [1, 2, 3].includes(4) // false [1, 2, NaN].includes(NaN) // true 复制代码 flat(n)n默认为1,表示拉平次数 //数组扁平化流氓解法 [1, [2, [3]]].flat(Infinity) 复制代码 flatMap()只能展开一层数组 // 相当于 [[[2]], [[4]], [[6]], [[8]]].flat() [1, 2, 3, 4].flatMap(x => [[x * 2]]) // [[2], [4], [6], [8]] 复制代码 4. 请问对象的拓展哪些属性? super关键字

this关键字总是指向函数所在的当前对象,而super指向当前对象的原型对象

const proto = { foo: 'hello' }; const obj = { foo: 'world', find() { return super.foo; } }; Object.setPrototypeOf(obj, proto); obj.find() // "hello" 复制代码 遍历方式 fo...in Object.keys() Reflect.ownKeys(obj)

返回一个数组

Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 }) // ['2', '10', 'b', 'a', Symbol()] 复制代码 新增方法

Object.is方法判断两个值是否同一个值

Object.assign方法用于对象的合并,复制到目标对象,且是浅拷贝

const target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3} 复制代码 5. 请问函数有哪些拓展呢? rest参数(...变量名) // arguments变量的写法 function sortNumbers() { return Array.from(arguments).sort(); } // rest参数的写法 const sortNumbers = (...numbers) => numbers.sort(); 复制代码 name属性 function foo() {} foo.name // "foo" 复制代码 箭头函数(常问普通函数的区别) 严格模式

只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。

6. 请问你见过的运算符拓展有哪些?

指数运算符(**)

2 ** 2 // 4 2 ** 3 // 8 // 相当于 2 ** (3 ** 2) 2 ** 3 ** 2 // 512 复制代码

看更多拓展可以参考链接运算符的扩展 - ECMAScript 6入门 (ruanyifeng.com)

- class继承篇 1. 请聊一下class继承 class可以通过extends关键字实现继承 Object.getPrototypeOf方法可以用来从子类上获取父类。 super这个关键字,,既可以当作函数使用,也可以当作对象使用。 子类的__ proto __ 属性,表示构造函数继承,总是指向父类 子类的prototype属性的__ proto __ 属性,表示方法的继承,总是指向父类的prototype属性 Mixin模式实现了继承多个类,参照以下写法 class DistributedEdit extends mix(Loggable, Serializable) { // ... } 复制代码 - promise篇(高频) 1. 请简述下promise的优缺点?

缺点:

无法取消Promise,一旦新建就会立即执行,无法中途取消 如果不设置回调函数,promise内部抛出的错误就无法反应到外部 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

优点:

解决回调地狱问题 代码扁平可读,.then方法链式调用 更好的进行错误捕获 2. 请聊一下promise.then() .catch() .finally()? 首先三者多是微任务 .then、.catch、.finally都会返回一个新的Promise .then方法能接受两个参数,第一个是处理成功的函数,第二个处理失败的函数 catch不管连接到哪一层,都能捕获上传未捕捉的错误。 .finally的回调函数不接受任何参数,也就是没法知道最终状态是resolved还是rejected的 3. 请聊下promise.all() promise.race()和promise.any()

promise.all:

同时处理多个promise对象,包装到一个新的Promise实例(常会被问到),如果传递的参数不是promise实例,他会调用promise.resolve方法,将参数转换实例

举个例子,p1,p2,p3都是promise对象

const p = Promise.all([p1, p2, p3]); 复制代码

其中p状态由p1,p2,p3,分成两种情况

只有p1,p2,p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值成一个数组,传递给p的回调函数 只要p1,p2,p3之中有一个被rejected,p的状态就变成rejected的实例返回值,会传递给p的回调函数

promise.race:

同时处理多个promise实例,包装成一个新的Promise实例,如果传递的参数不是promise实例,他会调用promise.resolve方法,将参数转换实例

还是以一个例子说明

const p = Promise.race([p1, p2, p3]); 复制代码

p只有一种情况,只要p1,p2,p3任意一个的状态发生改变,p的状态也随之发生改变。

promise.any:

也是同时处理promise实例,包装成一个新的promise实例。

它的状态变化跟promise.race类似,只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。

和promise.race()不同点,就是promise.any()不会因为某个promise变成rejected状态而结束,必须要等到所有的参数promise变成rejected状态才结束

4. promise手写系列

参考链接:

可能是目前最易理解的手写promise - 掘金 (juejin.cn)

手写Promise核心原理,再也不怕面试官问我Promise原理 - 掘金 (juejin.cn)

- 新增属性篇 1. 请聊一下ES6新增的数据类型symbol?

其最大的特点是:唯一值,独一无二的。

应用场景如下:

作为对象属性名(key) 使用symbol来代替常量 2. 请聊一下Proxy和Reflect?

回答步骤:

什么是proxy?

在目标对象之前架设一层拦截器,必须通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤修改。说上以下三点可以做的操作:

get(target,propKey,receiver):拦截对象属性读取

set(target,popKey,value,receiver):拦截对象属性的设置

has(target,propKey),拦截propKey in proxy的操作,以及对象的hasOwnProperty方法,返回一个布尔值

deleteProperty(target,propKey)拦截delete proxy[propKey]的操作,返回布尔值

​ ......

什么是Reflect?

它是一种于proxy对象一样,也是ES6新增的api,它的设计目的如下几点:

将Object对象的一些明显属于语言内部的方法 修改某些object方法的返回结果,让其变得更合理 让object操作都变成操作成为函数行为 // 老写法 'assign' in Object // true // 新写法 Reflect.has(Object, 'assign') // true 复制代码 reflect对象的方法与proxy对象一一对应,只要proxy对象,就能在proxy对象可以方便调用对应的reflect方法,完成默认行为,作为修改的基础,有了reflect对象更简单易懂 // 老写法 Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1 // 新写法 Reflect.apply(Math.floor, undefined, [1.75]) // 1 复制代码 3. 请聊下Genertor函数

直接开讲:

在语法上,首先可以把它理解成,Genertor函数是一个状态机,封装了多个内部状态 形式上,Generator函数是一个普通函数,两个特征。一是,function关键字与函数名之间有一个信号;二是,函数体内部状态(yield语句在英语里就是“产出”)

应用场景:

异步操作的同步化表达(异步操作的后续操作可以放在yield语句下面) 控制流管理 部署Iteratior接口 作为数据结构(可以看做一个数组结构,因为Genertor函数可以返回一系列的值) 4. 谈一下Iterator遍历器和for...of...

主要聊以下几个方面:

什么是Iterator(遍历器)?

是一种机制,它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据只要部署iterator接口,就可以完成遍历操作。

遍历器的作用 为各种数据结构,提供一个统一的、简便的访问接口 使得数据结构的成员能够按某种次序排列 ES6创造一种新的遍历命令for...of循环,Iterator接口主要提供for..of消费

注意:Object.prototype上没有没有实现[Symbol.iterator ](),所以不能for...of遍历

调用iterator接口的场合 结构赋值 拓展运算符(...) yield* [1,2,3,4] Promise.all(),Promise.race() Array.from() Map(),Set(),WeakMap(), WeakSet() 最后聊一下for...of

循环内部调用的是数据结构Symbol.iterator方法

for...of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。

ps: 参考链接

Proxy - ECMAScript 6入门 (ruanyifeng.com)



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3